﻿using System;
using System.Collections.Generic;
using System.Text;
using PCDoctor.Utils;
using Microsoft.Win32;

namespace PCDoctor.ScanParameters
{
    public class RegistryScanParameter : ScanParameter
    {
        public RegistryScanParameter(string name, string path, string value, Int64 problemId) :
            base(name, path, value, problemId)
        {
            Kind = ScanFixerKinds.Registy;
        }

        public override FixationResult Fix()
        {
            FixedProblems = 0;
            if (this.Result == ScanResult.OK)
            {
                FixResult = FixationResult.NoNeedToFix;
                return FixationResult.NoNeedToFix;
            }
            foreach (KeyValuePair<string, string> pv in PathsValues)
            {
                //Если с этим параметром все ок, то на него забиваем
                if (noNeedToFix.ContainsKey(pv.Key))
                {
                    if (noNeedToFix[pv.Key] == pv.Value)
                    {
                        continue;
                    }
                }
                RegistryKey currentKey = getKeyByPath(pv.Key);
                string valueName = getValueNameByPath(pv.Key);
                string valuePath = getValuePathByPath(pv.Key);
                //Расчленяем строку значения для получения типа и значения
                string[] valueParts = pv.Value.Split(':');
                string value = "";
                if (valueParts.Length == 1)
                {
                    value = valueParts[0];
                }
                else
                {
                    value = valueParts[1];
                }
                try
                {
                    RegistryKey rk = currentKey.OpenSubKey(valuePath, true);
                    if (rk == null)
                    {
                        rk = currentKey.CreateSubKey(valuePath);
                    }
                    object val = null;
                    RegistryValueKind vk = RegistryValueKind.DWord;
                    switch (valueParts[0])
                    {
                        case "dword":
                            val = long.Parse(value, System.Globalization.NumberStyles.AllowHexSpecifier);
                            vk = RegistryValueKind.DWord;
                            break;
                        default:
                            val = value;
                            vk = RegistryValueKind.String;
                            break;
                    }
                    rk.SetValue(valueName, val, vk);
                    rk.Close();
                    FixedProblems++;
                }
                catch (Exception)
                {
                    FixedProblems--;
                }
            }
            return base.Fix();
        }

        protected IDictionary<string, string> noNeedToFix = new Dictionary<string, string>();

        protected RegistryKey getKeyByPath(string path)
        {
            RegistryKey currentKey = null;
            //Расчленяем строку пути для получения раздела и ключа реестра
            string[] pathParts = path.Split('\\');
            switch (pathParts[0].ToUpper())
            {
                case "HKEY_LOCAL_MACHINE":
                    currentKey = Registry.LocalMachine;
                    break;
                case "HKEY_CURRENT_USER":
                    currentKey = Registry.CurrentUser;
                    break;
                case "HKEY_CLASSES_ROOT":
                    currentKey = Registry.ClassesRoot;
                    break;
            }
            return currentKey;
        }

        protected string getValuePathByPath(string path)
        {
            string[] pathParts = path.Split('\\');
            return path.Replace(pathParts[0] + "\\", "").
                Replace("\\" + pathParts[pathParts.Length - 1], "");
        }

        protected string getValueNameByPath(string path)
        {
            string[] pathParts = path.Split('\\');
            return pathParts[pathParts.Length - 1];
        }

        public override bool Scan()
        {
            ProblemsCount = 0;
            noNeedToFix.Clear();
            foreach (KeyValuePair<string, string> pv in PathsValues)
            {
                RegistryKey currentKey = getKeyByPath(pv.Key);
                string valueName = getValueNameByPath(pv.Key);
                string valuePath = getValuePathByPath(pv.Key);
                //Расчленяем строку значения для получения типа и значения
                string[] valueParts = pv.Value.Split(':');
                string value = "";
                if (valueParts.Length == 1)
                {
                    value = valueParts[0];
                }
                else
                {
                    value = valueParts[1];
                }
                try
                {
                    RegistryKey rk = currentKey.OpenSubKey(valuePath);
                    if (rk == null)
                    {
                        DoBackup(pv.Key, "___not_exists", valueName);
                        Result = ScanResult.Problem;
                        ProblemsCount++;
                    }
                    else
                    {
                        object obj = null;
                        string strObj = "";
                        switch (valueParts[0])
                        {
                            case "dword":
                                obj = Convert.ToInt64(rk.GetValue(valueName));
                                strObj = Convert.ToInt64(rk.GetValue(valueName)).ToString("X");
                                break;
                            default:
                                obj = (string)rk.GetValue(valueName);
                                strObj = obj.ToString();
                                break;
                        }
                        if (obj != null)
                        {
                            if (value.ToLower().Contains(strObj.ToLower()))
                            {
                                noNeedToFix.Add(pv.Key, pv.Value);
                                if (Result == ScanResult.NotScanned)
                                {
                                    Result = ScanResult.OK;
                                }
                            }
                            else
                            {
                                DoBackup(pv.Key, obj.ToString(), valueName);
                                Result = ScanResult.Problem;
                                ProblemsCount++;
                            }
                        }
                        else
                        {
                            DoBackup(pv.Key, "___not_exists", valueName);
                            Result = ScanResult.Problem;
                            ProblemsCount++;
                        }
                        rk.Close();
                    }
                }
                catch (Exception e)
                {
                    ErrorHandler.HandleError(Name + " " + e.Message);
                    Result = ScanResult.OK;
                }
            }
            if (ProblemsCount < 0)
            {
                ProblemsCount = -ProblemsCount;
                Result = ScanResult.OK;
            }
            return true;
        }

    }
}
